package com.lonwin.mes2u8.util;

import com.lonwin.mes2u8.common.CommonValue;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * HTTP请求相关工具类
 * @author DELL
 * @Date 2023-12-12 18:11
 */
@Slf4j
public class MyHttpClientUtil {

    /**
     * 将实体对象转换为get方式的url参数
     * @param object 实体对象
     * @return 组装好的参数
     */
    public static String convertGetParamByObj(Object object) {
        String param = "";
        Field[] fields = object.getClass().getDeclaredFields();
        param = Arrays.stream(fields).peek(o -> o.setAccessible(true))
                .filter(field -> {
                    try {
                        return Objects.nonNull(field.get(object));
                    } catch (IllegalAccessException e) {
                        log.error("convertGetParamByObj error 1 : get field value error");
                        throw new RuntimeException(e);
                    }
                })
                .map(field -> {
                            try {
                                return URLEncoder.encode(field.getName(), "UTF-8") + "=" + URLEncoder.encode(field.get(object).toString(), "UTF-8");
                            } catch (UnsupportedEncodingException e) {
                                log.error("convertGetParamByObj error 2 : urlencoding error");
                                throw new RuntimeException(e);
                            } catch (IllegalAccessException e) {
                                log.error("convertGetParamByObj error 3 : get field value error");
                                throw new RuntimeException(e);
                            }
                        }
                ).collect(Collectors.joining("&"));

        return param;
    }

    /**
     * 将Map集合对象转换为get方式的url参数
     * @param map 集全
     * @return
     */
    public static String convertGetParamByMap(Map<String, String> map) {
        return map.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("&"));

    }

    public static <T> T sendGetRequest(String url, String body, Function<HttpEntity, T> responseHandler) {
        log.info("HttpUtil.sendGetRequest start. url : {}, requestBody : {}", url, body);

        try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {

            // 创建get对象，组装请求参数
            if (StringUtils.isNotBlank(body)) {
                url = url + "?" + body;
            }
            HttpGet get = new HttpGet(url);

            // 发送请求，获取响应
            CloseableHttpResponse resp = httpClient.execute(get);

            StatusLine respStatus = resp.getStatusLine();

            if (CommonValue.HTTP_SUCCESS_CODE != respStatus.getStatusCode()) {
                log.info("HttpUtil.sendGetRequest 3 : response failed [{}]", resp.getEntity());
            }

            T t = responseHandler.apply(resp.getEntity());

            log.info("HttpUtil.sendGetRequest end");
            return t;

        } catch (IOException e) {
            log.debug(e.getMessage());
        }

        log.error("HttpUtil.sendGetRequest : 0 : create httpClient error ");
        return null;
    }

    public static <T> T sendPostRequest(String url, Map<String, String> header, String body, Function<HttpEntity, T> responseHandler) {
        log.info("HttpUtil.sendPostRequest start. url : {}, requestBody : {}", url, body);

        try(CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {

            // 创建post对象，组装请求参数
            HttpPost post = new HttpPost(url);
            if (StringUtils.isNotBlank(body)) {
                StringEntity stringEntity = new StringEntity(body, "UTF-8");
                post.setEntity(stringEntity);
            }
            if (Objects.nonNull(header) && !header.isEmpty()) {
                header.entrySet().forEach(entry -> post.setHeader(entry.getKey(), entry.getValue()));
            }
            post.setHeader("Content-Type", "application/json;charset=UTF-8");

            // 发送请求，获取响应
            CloseableHttpResponse resp = httpClient.execute(post);

            StatusLine respStatus = resp.getStatusLine();

            if (!(CommonValue.HTTP_SUCCESS_CODE == respStatus.getStatusCode())) {
                log.info("HttpUtil.sendPostRequest 3 : response failed [{}]", resp.getEntity());
            }

            T t = responseHandler.apply(resp.getEntity());

            log.info("HttpUtil.sendPostRequest end");
            return t;

        } catch (IOException e) {
            log.debug(e.getMessage());
        }

        log.error("HttpUtil.sendPostRequest : 0 : create httpClient error ");
        return null;
    }

    public static <T> T sendSSLGetRequest(String url, String body, Function<HttpEntity, T> responseHandler) {
        log.info("HttpUtil.sendSSLGETRequest start. url : {}, requestBody : {}", url, body);

        // 创建SSL上下文，用于绕过证书验证
        // SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build();
        // 创建SSL连接工厂，用于创建HTTPS连接
        // SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        // 创建HttpClient对象，并设置SSL连接工厂
        // HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        try(CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build(), NoopHostnameVerifier.INSTANCE)).build();
                ) {
            // 创建get对象，组装请求参数
            if (StringUtils.isNotBlank(body)) {
                url = url + "?" + body;
            }
            HttpGet get = new HttpGet(url);

            // 发送请求，获取响应
            CloseableHttpResponse resp = httpClient.execute(get);

            StatusLine respStatus = resp.getStatusLine();

            if (CommonValue.HTTP_SUCCESS_CODE != respStatus.getStatusCode()) {
                log.info("HttpUtil.sendGetRequest 3 : response failed [{}]", resp.getEntity());
            }

            T t = responseHandler.apply(resp.getEntity());

            log.info("HttpUtil.sendGetRequest end");
            return t;

        } catch (IOException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
            log.debug("HttpUtil.sendGetRequest occur exception : {}", e.getMessage());
        }

        log.error("HttpUtil.sendSSLGetRequest : 0 : create httpClient error ");
        return null;
    }


    public static <T> T sendSSLPostRequest(String url, Map<String, String> header, String body, Function<HttpEntity, T> responseHandler) {
        log.info("HttpUtil.sendSSLPostRequest start. url : {}, requestBody : {}", url, body);
        // 创建SSL上下文，用于绕过证书验证
        // SSLContext sslContext = SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build();
        // 创建SSL连接工厂，用于创建HTTPS连接
        // SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        // 创建HttpClient对象，并设置SSL连接工厂
        // HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        try(CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(new SSLConnectionSocketFactory(SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true).build(), NoopHostnameVerifier.INSTANCE)).build();
        ) {

            // 创建post对象，组装请求参数
            HttpPost post = new HttpPost(url);
            if (StringUtils.isNotBlank(body)) {
                StringEntity stringEntity = new StringEntity(body, "UTF-8");
                post.setEntity(stringEntity);
            }
            if (Objects.nonNull(header) && !header.isEmpty()) {
                header.entrySet().forEach(entry -> post.setHeader(entry.getKey(), entry.getValue()));
            }
            post.setHeader("Content-Type", "application/json;charset=UTF-8");

            // 发送请求，获取响应
            CloseableHttpResponse resp = httpClient.execute(post);

            StatusLine respStatus = resp.getStatusLine();

            if (!(CommonValue.HTTP_SUCCESS_CODE == respStatus.getStatusCode())) {
                log.info("HttpUtil.sendSSLPostRequest 3 : response failed [{}]", resp.getEntity());
            }

            T t = responseHandler.apply(resp.getEntity());

            log.info("HttpUtil.sendSSLPostRequest end");
            return t;

        } catch (IOException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
            log.debug("HttpUtil.sendSSLPostRequest occur exception: {}",e.getMessage());
        }

        log.error("HttpUtil.sendSSLPostRequest : 0 : create httpClient error ");
        return null;
    }

    public static String handleJsonResponse(HttpEntity entity) {
        StringBuilder sb = new StringBuilder();
        try {
            String body = null;
            InputStream content = entity.getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(content, StandardCharsets.UTF_8));
            while ((body = reader.readLine()) != null) {
                sb.append(body);
            }

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sb.toString();
    }
}
